Bingo, Computer Graphics & Game Developer

Unidirectional Path Tracing 3

Deprecated(2017.03.30)

这一篇主要记录PBRT中Path Tracing的理解笔记。一旦涉及到了代码层面的实现,会显得无从下手。

首先是路径追踪的蒙特卡洛估计量写法

Le(pipi1)f(pipi1pi2cosθi1)pA(pi)(j=1i2f(pi+1pjpj1)cosθj)pω(pj+1pj))\frac{L_e(p_i \to p_{i-1})f(p_i \to p_{i-1} \to p_{i-2}|cos\theta_{i-1}|)}{p_A(p_i)}(\prod^{i-2}_{j=1}\frac{f(p_{i+1} \to p_j \to p_{j-1})|cos\theta_j|)}{p_{\omega}(p_{j+1}-p_j)})

路径追踪加上了直接光采样,本质上就是应用重要性采样以及对于Dirac delta Distribution等的处理。


如图所示

使用一简化后的路径追踪表达式(省略了pdf,russian rullte,以及立体角到面积形式的表示,改变了累乘的上限)

Le(PiPi1)(j=1i1f(Pj+1PjPj1)cosθj)L_e(P_i \to P_{i-1})*(\prod_{j=1}^{i-1}f(P_{j+1} \to P_j \to P_{j-1})cos\theta_j)

意味着,当前追踪到的点上求得的直接光照,是用来计算上一节点的Reflected Radiance的。令EE表示光源,那么直接光采样得到的结果,表示当前点PiP_i位置处,向PiPi1P_i \to P_{i-1}反射的光照,因此需要在计算直接光照时,乘以权重(仅表意,严格来讲这里是做了一次多重重要性采样)

Le(PiPi1)=Le(EPi)f(Pi,wEi,wii1)cosθi1pdfL_e(P_i \to P_{i-1})=L_e(E \to P_i)*\frac{f(P_i,w_{E \to i},w_{i \to i-1})cos\theta_{i-1}}{pdf}

因此这里PiP_i点处计算得到的直接光照,被用于点PiP_i用作间接光照/反射光来传递给下一节点。由于运用了光路可逆,因此在代码实现过程中循环过程会是相反的,也就是正向追踪光路。

这一事实较难以直接从公式中get到,下方通过PBRT源代码验证。

PBRT通过保存一个pathThroughput变量,用于记录原式子右边的累乘项

j=1i2f(pi+1pjpj1)cosθj)pω(pj+1pj)\prod^{i-2}_{j=1}\frac{f(p_{i+1} \to p_j \to p_{j-1})|cos\theta_j|)}{p_{\omega}(p_{j+1}-p_{j})}

    for (int bounces = 0; ; ++bounces) 
    {
        // 逆向计算直接光照在上一节点的贡献/反射光照
        Vector wo = -ray.d;
        L += pathThroughput * UniformSampleOneLight(wo,...);

        // 计算当前结点BRDF以及出射方向
        Spectrum f = bsdf->Sample_f(wo, wi, pdf...);

        // 式子中的累乘项,晚于直接光照的计算
        pathThroughput *= f * AbsDot(wi, n) / pdf;

        // 新的跟踪光线
        ray = Ray(p, wi, ...);

        if (bounces == maxDepth) break;

        if (!scene->Intersect(ray,...)) 
        {
            // 无限远区域光光照
            L += pathThroughput * infiniteLight;
            break;
        }
    }
    return L;

因此在理解增量形式路径追踪的实际实现时,最关键的点为以下两点

1.当前追踪到的点上计算得到的直接光照,是作用于上一节点的反射光照上的。

2.循环中累乘项应晚于直接光照计算,因此其累乘项截止到上一节点为止。